<template>
  <div>
    <el-tabs type="border-card">
      <el-tab-pane label="秒" v-if="shouldHide('second')">
        <CrontabSecond
          @update="updateCrontabValue"
          :check="checkNumber"
          :cron="crontabValueObj"
          :radioParent="myindex"
          ref="cronsecond"
        />
      </el-tab-pane>

      <el-tab-pane label="分钟" v-if="shouldHide('min')">
        <CrontabMin
          @update="updateCrontabValue"
          :check="checkNumber"
          :cron="crontabValueObj"
          ref="cronmin"
        />
      </el-tab-pane>

      <el-tab-pane label="小时" v-if="shouldHide('hour')">
        <CrontabHour
          @update="updateCrontabValue"
          :check="checkNumber"
          :cron="crontabValueObj"
          ref="cronhour"
        />
      </el-tab-pane>

      <el-tab-pane label="日" v-if="shouldHide('day')">
        <CrontabDay
          @update="updateCrontabValue"
          :check="checkNumber"
          :cron="crontabValueObj"
          ref="cronday"
        />
      </el-tab-pane>

      <el-tab-pane label="月" v-if="shouldHide('month')">
        <CrontabMonth
          @update="updateCrontabValue"
          :check="checkNumber"
          :cron="crontabValueObj"
          ref="cronmonth"
        />
      </el-tab-pane>

      <el-tab-pane label="周" v-if="shouldHide('week')">
        <CrontabWeek
          @update="updateCrontabValue"
          :check="checkNumber"
          :cron="crontabValueObj"
          ref="cronweek"
        />
      </el-tab-pane>

      <el-tab-pane label="年" v-if="shouldHide('year')">
        <CrontabYear
          @update="updateCrontabValue"
          :check="checkNumber"
          :month="crontabValueObj.month"
          :cron="crontabValueObj"
          ref="cronyear"
        />
      </el-tab-pane>
    </el-tabs>

    <div class="popup-main">
      <div class="popup-result">
        <p class="title">时间表达式</p>
        <table>
          <thead>
            <th v-for="item of tabTitles" width="40" :key="item">{{ item }}</th>
            <th>Cron 表达式</th>
          </thead>
          <tbody>
            <td>
              <span>{{ crontabValueObj.second }}</span>
            </td>
            <td>
              <span>{{ crontabValueObj.min }}</span>
            </td>
            <td>
              <span>{{ crontabValueObj.hour }}</span>
            </td>
            <td>
              <span>{{ crontabValueObj.day }}</span>
            </td>
            <td>
              <span>{{ crontabValueObj.month }}</span>
            </td>
            <td>
              <span>{{ crontabValueObj.week }}</span>
            </td>
            <td>
              <span>{{ crontabValueObj.year }}</span>
            </td>
            <td>
              <span>{{ crontabValueString }}</span>
            </td>
          </tbody>
        </table>
      </div>
      <CrontabResult :ex="crontabValueString"></CrontabResult>

      <div class="pop_btn">
        <el-button size="small" type="primary" @click="submitFill">确定</el-button>
        <el-button size="small" type="warning" @click="clearCron">重置</el-button>
        <el-button size="small" @click="hidePopup">取消</el-button>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import CrontabSecond from './second.vue'
import CrontabMin from './min.vue'
import CrontabHour from './hour.vue'
import CrontabDay from './day.vue'
import CrontabMonth from './month.vue'
import CrontabWeek from './week.vue'
import CrontabYear from './year.vue'
import CrontabResult from './result.vue'

interface CronTabValue {
  second: string
  min: string
  hour: string
  day: string
  month: string
  week: string
  year: string
}

interface Props {
  expression?: string
  hideComponent?: string[]
}

const props = withDefaults(defineProps<Props>(), {
  expression: '',
  hideComponent: () => [],
})

const emit = defineEmits<{
  (e: 'hide'): void
  (e: 'fill', value: string): void
}>()

const tabTitles = ref(['秒', '分钟', '小时', '日', '月', '周', '年'])
const tabActive = ref(0)
const myindex = ref(0)
const crontabValueObj = ref<CronTabValue>({
  second: '*',
  min: '*',
  hour: '*',
  day: '*',
  month: '*',
  week: '?',
  year: '',
})

// 定义所有子组件的引用类型
const cronsecond = ref<InstanceType<typeof CrontabSecond> | null>(null)
const cronmin = ref<InstanceType<typeof CrontabMin> | null>(null)
const cronhour = ref<InstanceType<typeof CrontabHour> | null>(null)
const cronday = ref<InstanceType<typeof CrontabDay> | null>(null)
const cronmonth = ref<InstanceType<typeof CrontabMonth> | null>(null)
const cronweek = ref<InstanceType<typeof CrontabWeek> | null>(null)
const cronyear = ref<InstanceType<typeof CrontabYear> | null>(null)

const shouldHide = (key: string) => {
  if (props.hideComponent && props.hideComponent.includes(key)) return false
  return true
}

const resolveExp = () => {
  // 反解析 表达式
  if (props.expression) {
    const arr = props.expression.split(' ')
    if (arr.length >= 6) {
      //6 位以上是合法表达式
      const obj: CronTabValue = {
        second: arr[0] || '*',
        min: arr[1] || '*',
        hour: arr[2] || '*',
        day: arr[3] || '*',
        month: arr[4] || '*',
        week: arr[5] || '?',
        year: arr[6] ? arr[6] : '',
      }
      crontabValueObj.value = obj
      for (const i in obj) {
        changeRadio(i, obj[i as keyof CronTabValue])
      }
    }
  } else {
    // 没有传入的表达式 则还原
    clearCron()
  }
}

// tab切换值
const tabCheck = (index: number) => {
  tabActive.value = index
}

// 由子组件触发，更改表达式组成的字段值
const updateCrontabValue = (name: string, value: string, from?: string) => {
  console.log('updateCrontabValue', name, value, from)
  crontabValueObj.value[name as keyof CronTabValue] = value
  if (from && from !== name) {
    console.log(`来自组件 ${from} 改变了 ${name} ${value}`)
    changeRadio(name, value)
  }
}

// 赋值到组件
const changeRadio = (name: string, value: string) => {
  const arr = ['second', 'min', 'hour', 'month']
  let insValue: number | undefined

  // Get the correct ref based on name
  let componentRef: any = null
  switch (name) {
    case 'second':
      componentRef = cronsecond.value
      break
    case 'min':
      componentRef = cronmin.value
      break
    case 'hour':
      componentRef = cronhour.value
      break
    case 'day':
      componentRef = cronday.value
      break
    case 'month':
      componentRef = cronmonth.value
      break
    case 'week':
      componentRef = cronweek.value
      break
    case 'year':
      componentRef = cronyear.value
      break
  }

  if (!componentRef) return

  if (arr.includes(name)) {
    if (value === '*') {
      insValue = 1
    } else if (value.indexOf('-') > -1) {
      const indexArr = value.split('-')
      componentRef.cycle01 = isNaN(Number(indexArr[0])) ? 0 : Number(indexArr[0])
      componentRef.cycle02 = Number(indexArr[1])
      insValue = 2
    } else if (value.indexOf('/') > -1) {
      const indexArr = value.split('/')
      componentRef.average01 = isNaN(Number(indexArr[0])) ? 0 : Number(indexArr[0])
      componentRef.average02 = Number(indexArr[1])
      insValue = 3
    } else {
      insValue = 4
      componentRef.checkboxList = value.split(',')
    }
  } else if (name == 'day') {
    if (value === '*') {
      insValue = 1
    } else if (value == '?') {
      insValue = 2
    } else if (value.indexOf('-') > -1) {
      const indexArr = value.split('-')
      componentRef.cycle01 = isNaN(Number(indexArr[0])) ? 0 : Number(indexArr[0])
      componentRef.cycle02 = Number(indexArr[1])
      insValue = 3
    } else if (value.indexOf('/') > -1) {
      const indexArr = value.split('/')
      componentRef.average01 = isNaN(Number(indexArr[0])) ? 0 : Number(indexArr[0])
      componentRef.average02 = Number(indexArr[1])
      insValue = 4
    } else if (value.indexOf('W') > -1) {
      const indexArr = value.split('W')
      componentRef.workday = isNaN(Number(indexArr[0])) ? 0 : Number(indexArr[0])
      insValue = 5
    } else if (value === 'L') {
      insValue = 6
    } else {
      componentRef.checkboxList = value.split(',')
      insValue = 7
    }
  } else if (name == 'week') {
    if (value === '*') {
      insValue = 1
    } else if (value == '?') {
      insValue = 2
    } else if (value.indexOf('-') > -1) {
      const indexArr = value.split('-')
      componentRef.cycle01 = isNaN(Number(indexArr[0])) ? 0 : Number(indexArr[0])
      componentRef.cycle02 = Number(indexArr[1])
      insValue = 3
    } else if (value.indexOf('#') > -1) {
      const indexArr = value.split('#')
      componentRef.average01 = isNaN(Number(indexArr[0])) ? 1 : Number(indexArr[0])
      componentRef.average02 = Number(indexArr[1])
      insValue = 4
    } else if (value.indexOf('L') > -1) {
      const indexArr = value.split('L')
      componentRef.weekday = isNaN(Number(indexArr[0])) ? 1 : Number(indexArr[0])
      insValue = 5
    } else {
      componentRef.checkboxList = value.split(',')
      insValue = 6
    }
  } else if (name == 'year') {
    if (value == '') {
      insValue = 1
    } else if (value == '*') {
      insValue = 2
    } else if (value.indexOf('-') > -1) {
      insValue = 3
    } else if (value.indexOf('/') > -1) {
      insValue = 4
    } else {
      componentRef.checkboxList = value.split(',')
      insValue = 5
    }
  }

  if (insValue !== undefined) {
    componentRef.radioValue = insValue
  }
}

// 表单选项的子组件校验数字格式（通过-props传递）
const checkNumber = (value: number, minLimit: number, maxLimit: number) => {
  // 检查必须为整数
  value = Math.floor(value)
  if (value < minLimit) {
    value = minLimit
  } else if (value > maxLimit) {
    value = maxLimit
  }
  return value
}

// 隐藏弹窗
const hidePopup = () => {
  emit('hide')
}

// 填充表达式
const submitFill = () => {
  emit('fill', crontabValueString.value)
  hidePopup()
}

const clearCron = () => {
  // 还原选择项
  console.log('准备还原')
  crontabValueObj.value = {
    second: '*',
    min: '*',
    hour: '*',
    day: '*',
    month: '*',
    week: '?',
    year: '',
  }
  for (const j in crontabValueObj.value) {
    changeRadio(j, crontabValueObj.value[j as keyof CronTabValue])
  }
}

const crontabValueString = computed(() => {
  const obj = crontabValueObj.value
  const str =
    obj.second +
    ' ' +
    obj.min +
    ' ' +
    obj.hour +
    ' ' +
    obj.day +
    ' ' +
    obj.month +
    ' ' +
    obj.week +
    (obj.year == '' ? '' : ' ' + obj.year)
  return str
})

watch(() => props.expression, resolveExp)
watch(
  () => props.hideComponent,
  (value) => {
    // 隐藏部分组件
  },
)

onMounted(() => {
  resolveExp()
})
</script>

<style scoped>
.pop_btn {
  text-align: center;
  margin-top: 20px;
}
.popup-main {
  position: relative;
  margin: 10px auto;
  background: #fff;
  border-radius: 5px;
  font-size: 12px;
  overflow: hidden;
}
.popup-title {
  overflow: hidden;
  line-height: 34px;
  padding-top: 6px;
  background: #f2f2f2;
}
.popup-result {
  box-sizing: border-box;
  line-height: 24px;
  margin: 25px auto;
  padding: 15px 10px 10px;
  border: 1px solid #ccc;
  position: relative;
}
.popup-result .title {
  position: absolute;
  top: -28px;
  left: 50%;
  width: 140px;
  font-size: 14px;
  margin-left: -70px;
  text-align: center;
  line-height: 30px;
  background: #fff;
}
.popup-result table {
  text-align: center;
  width: 100%;
  margin: 0 auto;
}
.popup-result table span {
  display: block;
  width: 100%;
  font-family: arial;
  line-height: 30px;
  height: 30px;
  white-space: nowrap;
  overflow: hidden;
  border: 1px solid #e8e8e8;
}
.popup-result-scroll {
  font-size: 12px;
  line-height: 24px;
  height: 10em;
  overflow-y: auto;
}
</style>
